I processi (task) Un task (o processo in italiano) dovrebbe essere oramai chiaro a tutti cosa sia, infatti altro non è che un programma (in inglese vuol dire lavoro o mansione); dato che il s.o. dell'Amiga è multitasking appare ovvio, che più task possono essere attivi contemporeanemente e quindi risulta logico che il programma principale possa attivare un secondo task che procede parallelamente. Un task è identificato da una struttura denominata "Task" che mantiene tutte le informazioni relative alla creazione ed alla vita del processo; è possibile ottenere il puntatore a tale struttura del task in esecuzione mediante la chiamata: processo = FindTask(NULL); il task in esecuzione di cui verrà ritornato il valore "processo" puntatore alla struttura Task, è sicuramente quello che esegue la chiamata alla funzione appena vista; se si vuole ricerca un task in particolare, bisogna invece specificare la stringa indicante il nome che lo identifica nella lista. Per la creazione di un processo occorre allocare la memoria della struttura Task mediante AllocMem con attributi MEMF_CLEAR e MEM_PUBLIC; in tal modo la struttura verrà inizializzata con zero e sarà di tipo condivisibile; i campi da inizializzare della struttura Task dipendono da come intendi utilizzare il processo; nel caso più semplice occorre inizializzare i seguenti campi: tc_Node - dato che il processo verrà inserito nella lista dei task del sistema occorre inizializzare il nodo con le informazioni relative alla priorità, il tipo ed il nome. tc_SPLower - il limite di memoria inferiore dello stack del task tc_SPUpper - il limite di memoria superiore dello stack tc_SPReg - il valore iniziale dello stack pointer (SP) bisogna porre a zero tutti gli altri campi (ma allocando la memoria della struttura con MEMF_CLEAR viene già fatto). Una volta che la struttura Task è inizializzata il processo può essere reso attivo con AddTask: AddTask(processo,PCiniziale,PCfinale); dove "processo" è il puntatore alla struttura Task contenente i dati relativi alla creazione del task; PCiniziale è l'indirizzo della prima istruzione del task da eseguire e PCfinale è l'indirizzo della procedura che verrà eseguita all'uscita del task (con PCfinale uguale a NULL ne viene implementata una standard di exec); dalla versione 2 del s.o. AddTask ritorna l'indirizzo del task o NULL in caso in cui l'operazione ha fallito. Per rimuovere il task (che potrebbe essere già stato rimosso nel caso la sua esecuzione sia giunta al termine) occorre utilizzare RemTask: RemTask(processo); Lo stesso lavoro per la creazione di un task può essere effettuata con una singola chiamata a CreateTask (una macro di amiga.lib): processo = (struct Task *)CreateTask(nome,priorità,PCiniziale,grandstack); dove "nome" è il nome che avrà il task nella lista, "priorità" è la sua priorità, "PCiniziale" l'indirizzo della prima istruzione del task e "grandstack" la grandezza in bytes dello stack per il task; occorre far attenzione alla grandezza dello stack (che con AddTask deve essere allocato dal programma, mentre con CreateTask è fatto automaticamente) perché questo non solo dipende dalla quantità di dati che vengono posti sullo stack dal suo task, ma anche dal s.o., poiché nel task-switching i registri del task congelato vengono memorizzati proprio nel suo stack per essere poi ripresi quando verrà riattivato (si consiglia un minimo di 256 bytes); per "eliminare" un task creato con CreateTask prima del suo tempo occorre eseguire DeleteTask: DeleteTask(processo); Fare attenzione che prima che un task venga eliminato, tutte le risorse allocate da quest'ultimo (memoria, librerie ecc.) devono essere liberate; per maggior sicurezza conviene che, tutte le risorse che necessitano al task figlio (quello da creare) vengano allocate dal task padre (il processo che crea il task figlio). Abbiamo ultimato l'argomento dei task anche se vi sono altre importanti caratteristiche come il trattamento dei traps del task che vedremo eventualmente di trattare in un articolo a parte.